import { Injectable, Logger } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository, DataSource, LessThan } from "typeorm";
import {
  CasinoDiceBet,
  CasinoChibiBet,
  GameType,
  BetType,
  BetStatus,
  DiceResultData,
  ChibiResultData,
} from "../entities";
import { getBetTypeFullName } from "../enums/bet-type-mapping.enum";
import { DiceRoundStatus } from "../entities/casino-dice-round.entity";
import { ChibiRoundStatus } from "../entities/casino-chibi-round.entity";
import { CharacterResourcesEntity } from "../../../entities/character-resources.entity";
import { casinoConfig } from "../config/casino.config";
import {
  CasinoBroadcastMessage,
  DiceBroadcastMessage,
  ChibiBroadcastMessage,
} from "../interfaces/casino.interface";
import { CasinoUnifiedRoundService } from "./casino-unified-round.service";
import { CasinoDiceRoundService } from "./casino-dice-round.service";
import { CasinoChibiRoundService } from "./casino-chibi-round.service";
import { RedisService } from "../../../services/redis.service";
import { SystemMessageService } from "../../../services/system-message.service";
import { CharacterEntity } from "../../../entities/character.entity";

@Injectable()
export class CasinoSettlementService {
  private readonly logger = new Logger(CasinoSettlementService.name);

  constructor(
    @InjectRepository(CasinoDiceBet)
    private readonly diceBetRepository: Repository<CasinoDiceBet>,
    @InjectRepository(CasinoChibiBet)
    private readonly chibiBetRepository: Repository<CasinoChibiBet>,
    @InjectRepository(CharacterResourcesEntity)
    private readonly characterResourcesRepository: Repository<CharacterResourcesEntity>,
    @InjectRepository(CharacterEntity)
    private readonly characterRepository: Repository<CharacterEntity>,
    private readonly dataSource: DataSource,
    private readonly roundService: CasinoUnifiedRoundService,
    private readonly diceRoundService: CasinoDiceRoundService,
    private readonly chibiRoundService: CasinoChibiRoundService,
    private readonly redisService: RedisService,
    private readonly systemMessageService: SystemMessageService
  ) {}

  // ==================== 大小玩法结算 ====================

  /**
   * 结算大小玩法
   */
  async settleDiceRound(roundId: number): Promise<void> {
    try {
      // 直接使用分离期数服务获取期数信息
      const round = await this.diceRoundService.getRoundById(roundId);

      if (!round || round.status !== DiceRoundStatus.DRAWING) {
        throw new Error("期数状态不正确");
      }

      // 验证开奖结果是否完整（三个筛子都有值）
      if (
        round.num1 === null ||
        round.num1 === undefined ||
        round.num2 === null ||
        round.num2 === undefined ||
        round.num3 === null ||
        round.num3 === undefined
      ) {
        throw new Error("期数开奖结果不完整，无法进行结算");
      }

      this.logger.log(
        `开始结算大小玩法期数 ${roundId}，开奖结果: ${round.num1}, ${round.num2}, ${round.num3}`
      );

      // 使用已有的开奖结果，而不是重新生成
      const sum = round.num1 + round.num2 + round.num3;
      const result: DiceResultData = {
        num1: round.num1,
        num2: round.num2,
        num3: round.num3,
        sum: round.sum || sum,
        isBig: Boolean(round.isBig) || sum > 10,
        isSmall: Boolean(round.isSmall) || sum <= 10,
        isOdd: Boolean(round.isOdd) || sum % 2 === 1,
        isEven: Boolean(round.isEven) || sum % 2 === 0,
        isTriple:
          Boolean(round.isTriple) ||
          (round.num1 === round.num2 && round.num2 === round.num3),
      };

      // 计算中奖金额
      await this.calculateDiceWinnings(roundId, result);

      // 更新期数状态和结果
      await this.diceRoundService.updateRoundStatus(
        roundId,
        DiceRoundStatus.SETTLED
      );

      // 保存开奖结果到数据库
      await this.diceRoundService.updateRoundResult(roundId, result);

      // 广播开奖结果给所有在线用户
      await this.broadcastDiceResult(roundId, result);

      this.logger.log(`✅ 期数 ${roundId} 大小玩法结算完成`);
    } catch (error: any) {
      this.logger.error(
        `❌ 结算大小玩法期数 ${roundId} 失败:`,
        error?.message || error
      );
      throw error;
    }
  }

  /**
   * 结算赤壁玩法
   */
  async settleChibiRound(roundId: number): Promise<void> {
    try {
      // 直接使用分离期数服务获取期数信息
      const round = await this.chibiRoundService.getRoundById(roundId);

      if (!round || round.status !== ChibiRoundStatus.DRAWING) {
        throw new Error("期数状态不正确");
      }

      // 验证开奖结果是否完整（获胜国家已确定）
      if (
        round.winningSide === null ||
        round.winningSide === undefined ||
        round.winningSide < 1 ||
        round.winningSide > 3
      ) {
        throw new Error("期数开奖结果不完整，无法进行结算");
      }

      this.logger.log(
        `开始结算赤壁玩法期数 ${roundId}，获胜国家: ${round.winningSide}`
      );

      // 获取该期数的所有下注数据
      const bets = await this.chibiBetRepository.find({
        where: { roundId, status: BetStatus.BETTING },
      });

      // 使用已有的开奖结果，而不是重新生成
      const result: ChibiResultData = {
        winningSide: round.winningSide,
        battleReport:
          round.battleReport || this.generateBattleReport(round.winningSide),
        sideStats: {
          1: round.weiTotalGold + round.weiTotalSilver,
          2: round.shuTotalGold + round.shuTotalSilver,
          3: round.wuTotalGold + round.wuTotalSilver,
        },
        reportStr:
          round.reportStr || this.generateBattleReport(round.winningSide),
      };

      // 计算中奖金额
      await this.calculateChibiWinnings(roundId, result);

      // 更新期数状态和结果
      await this.chibiRoundService.updateRoundStatus(
        roundId,
        ChibiRoundStatus.SETTLED
      );

      // 保存开奖结果到数据库
      await this.chibiRoundService.updateRoundResult(roundId, result);

      // 广播开奖结果给所有在线用户
      await this.broadcastChibiResult(roundId, result);

      this.logger.log(`✅ 期数 ${roundId} 赤壁玩法结算完成`);
    } catch (error: any) {
      this.logger.error(
        `❌ 结算赤壁玩法期数 ${roundId} 失败:`,
        error?.message || error
      );
      throw error;
    }
  }

  /**
   * 生成大小玩法开奖结果
   */
  private generateDiceResult(): DiceResultData {
    const num1 = Math.floor(Math.random() * 6) + 1;
    const num2 = Math.floor(Math.random() * 6) + 1;
    const num3 = Math.floor(Math.random() * 6) + 1;

    const sum = num1 + num2 + num3;
    const isBig = sum > 10;
    const isSmall = sum <= 10;
    const isOdd = sum % 2 === 1;
    const isEven = sum % 2 === 0;
    const isTriple = num1 === num2 && num2 === num3;

    return {
      num1,
      num2,
      num3,
      sum,
      isBig,
      isSmall,
      isOdd,
      isEven,
      isTriple,
    };
  }

  /**
   * 生成赤壁玩法开奖结果
   */
  private generateChibiResult(bets: CasinoChibiBet[]): ChibiResultData {
    // 统计各国下注情况（用于显示和计算奖励）
    const sideStats = { 1: 0, 2: 0, 3: 0 };

    bets.forEach((bet) => {
      sideStats[bet.side] +=
        Number(bet.betGold || 0) + Number(bet.betSilver || 0);
    });

    // 平等概率随机选择获胜国家（1/3概率）
    const winningSide = Math.floor(Math.random() * 3) + 1;

    this.logger.log(
      `赤壁开奖结果: ${this.getSideName(winningSide)}获胜，下注统计: 魏国${
        sideStats[1]
      }，蜀国${sideStats[2]}，吴国${sideStats[3]}`
    );

    return {
      winningSide,
      battleReport: this.generateBattleReport(winningSide),
      sideStats,
      reportStr: this.generateBattleReport(winningSide),
    };
  }

  /**
   * 生成战报描述
   */
  private generateBattleReport(winningSide: number): string {
    const reports: { [key: number]: string[] } = {
      1: [
        "魏军大获全胜，敌军溃不成军",
        "魏国铁骑横扫千军",
        "魏国弓箭手万箭齐发",
        "魏国军师神机妙算，克敌制胜",
      ],
      2: [
        "蜀军奇谋妙计，大破敌军",
        "蜀国神箭手百步穿杨",
        "蜀国骑兵冲锋陷阵",
        "蜀国将领勇猛无双，所向披靡",
      ],
      3: [
        "吴军水师无敌，敌军望风而逃",
        "吴国火攻计策，火烧连营",
        "吴国水军乘风破浪",
        "吴国统帅运筹帷幄，决胜千里",
      ],
    };

    const sideReports = reports[winningSide] || reports[1];
    return sideReports[Math.floor(Math.random() * sideReports.length)];
  }

  /**
   * 计算大小玩法中奖金额
   */
  private async calculateDiceWinnings(
    roundId: number,
    result: DiceResultData
  ): Promise<void> {
    try {
      const bets = await this.diceBetRepository.find({
        where: { roundId, status: BetStatus.BETTING },
      });

      for (const bet of bets) {
        let isWin = false;
        let multiplier = 1;

        // 豹子通吃逻辑：如果开豹子，只有豹子下注中奖，其他都算输
        if (result.isTriple) {
          // 开豹子时
          if (bet.betType === BetType.TRIPLE) {
            // 豹子下注中奖
            isWin = true;
            multiplier = 10;
          } else {
            // 其他下注类型（大小单双）都算输
            isWin = false;
            multiplier = 1;
          }
        } else {
          // 非豹子时，正常判断
          switch (bet.betType) {
            case BetType.BIG:
              isWin = result.isBig;
              multiplier = 2;
              break;
            case BetType.SMALL:
              isWin = result.isSmall;
              multiplier = 2;
              break;
            case BetType.ODD:
              isWin = result.isOdd;
              multiplier = 2;
              break;
            case BetType.EVEN:
              isWin = result.isEven;
              multiplier = 2;
              break;
            case BetType.TRIPLE:
              isWin = result.isTriple;
              multiplier = 10;
              break;
          }
        }

        // 更新下注状态
        if (isWin) {
          // 计算中奖金额（扣除手续费，保留整数）
          const rawWinnings = Number(bet.betAmount) * multiplier;
          bet.winAmount = Number(
            Math.floor(rawWinnings * casinoConfig.fees.winningMultiplier)
          );
          bet.status = BetStatus.SETTLED; // 中奖时设置为已结算状态
        } else {
          bet.winAmount = 0; // 确保未中奖时也是数字0
          bet.status = BetStatus.SETTLED; // 修改：未中奖时也设置为已结算状态
        }

        await this.diceBetRepository.save(bet);

        // 发放奖励
        if (isWin) {
          await this.distributeWinnings(
            bet.characterId,
            Number(bet.winAmount), // 确保传入数字类型
            bet.currencyType
          );

          // 发送中奖系统消息给玩家
          await this.sendWinningSystemMessage(
            bet.characterId,
            "大小玩法",
            bet.winAmount,
            bet.currencyType,
            `恭喜,您在猜猜猜中下注${bet.betTypeName}赢得${bet.winAmount}${
              bet.currencyType === 1 ? "金砖" : "银子"
            }！`
          );

          this.logger.log(
            `用户 ${bet.characterId} 中奖，获得 ${bet.winAmount} ${
              bet.currencyType === 1 ? "金币" : "银币"
            } (扣除${(casinoConfig.fees.winningCommission * 100).toFixed(
              0
            )}%手续费后)`
          );
        } else {
          // 发送中奖系统消息给玩家
          await this.sendWinningSystemMessage(
            bet.characterId,
            "大小玩法",
            bet.winAmount,
            bet.currencyType,
            `很遗憾,您在猜猜猜中下注${bet.betTypeName}输掉${bet.betAmount}${
              bet.currencyType === 1 ? "金砖" : "银子"
            }！`
          );
        }
      }
    } catch (error: any) {
      this.logger.error(`计算大小玩法中奖金额失败:`, error?.message || error);
      throw error;
    }
  }

  /**
   * 计算赤壁玩法中奖金额
   * 中间金额计算方式：下注金额 × 3倍 × winningMultiplier
   * 倍数是3因为总共三个国家，中间三个之一概率
   */
  private async calculateChibiWinnings(
    roundId: number,
    result: ChibiResultData
  ): Promise<void> {
    try {
      const bets = await this.chibiBetRepository.find({
        where: { roundId, status: BetStatus.BETTING },
      });

      // 赤壁玩法固定倍数：3倍（因为三个国家中选一个获胜）
      const CHIBI_MULTIPLIER = 3;

      for (const bet of bets) {
        if (bet.side === result.winningSide) {
          // 获胜方：下注金额 × 3倍 × winningMultiplier
          const rawWinGold = bet.betGold * CHIBI_MULTIPLIER;
          const rawWinSilver = bet.betSilver * CHIBI_MULTIPLIER;

          // 计算中奖金额（扣除手续费，保留整数）
          bet.winGold = Number(
            Math.max(
              0,
              Math.min(
                Number.MAX_SAFE_INTEGER,
                Math.floor(rawWinGold * casinoConfig.fees.winningMultiplier)
              )
            )
          );
          bet.winSilver = Number(
            Math.max(
              0,
              Math.min(
                Number.MAX_SAFE_INTEGER,
                Math.floor(rawWinSilver * casinoConfig.fees.winningMultiplier)
              )
            )
          );
          bet.status = BetStatus.SETTLED; // 修改：中奖时设置为已结算状态

          await this.chibiBetRepository.save(bet);

          // 发放奖励
          if (bet.winGold > 0) {
            await this.distributeWinnings(
              bet.characterId,
              Number(bet.winGold),
              1
            );
          }
          if (bet.winSilver > 0) {
            await this.distributeWinnings(
              bet.characterId,
              Number(bet.winSilver),
              2
            );
          }

          // 发送中奖系统消息给玩家
          await this.sendWinningSystemMessage(
            bet.characterId,
            "赤壁玩法",
            bet.winGold + bet.winSilver,
            bet.winGold > 0 ? 1 : 2,
            `恭喜,您在三国鸭中下注${this.getSideName(bet.side)}赢得${
              bet.winGold > 0 ? bet.winGold + "金砖" : ""
            }${bet.winSilver > 0 ? bet.winSilver + "银子" : ""}！`
          );

          this.logger.log(
            `用户 ${bet.characterId} 支援 ${this.getSideName(
              bet.side
            )} 获胜，获得 ${bet.winGold} 金币 ${
              bet.winSilver
            } 银币 (${CHIBI_MULTIPLIER}倍扣除${(
              casinoConfig.fees.winningCommission * 100
            ).toFixed(0)}%手续费后)`
          );
        } else {
          bet.winGold = 0; // 确保未中奖时也是数字0
          bet.winSilver = 0; // 确保未中奖时也是数字0
          bet.status = BetStatus.SETTLED; // 修改：未中奖时也设置为已结算状态
          await this.chibiBetRepository.save(bet);
        }
      }
    } catch (error: any) {
      this.logger.error(`计算赤壁玩法中奖金额失败:`, error?.message || error);
      throw error;
    }
  }

  /**
   * 分配奖金
   */
  private async distributeWinnings(
    characterId: number, // userId 就是 characterId
    amount: number,
    currencyType: number // 1:金币 2:银币
  ): Promise<void> {
    try {
      // userId 就是 characterId，直接更新 character_resources 表
      await this.characterResourcesRepository.increment(
        { characterId: characterId },
        currencyType === 1 ? "gold" : "silver",
        amount
      );

      this.logger.log(
        `✅ 成功为用户 ${characterId} 分配 ${amount} ${this.getCurrencyName(
          currencyType
        )}`
      );
    } catch (error: any) {
      this.logger.error(`分配奖金失败:`, error?.message || error);
      throw error;
    }
  }

  /**
   * 发送赤壁开奖广播通知
   */
  private async broadcastChibiResult(
    roundId: number,
    result: ChibiResultData
  ): Promise<void> {
    try {
      // 查询本期所有下注，计算开奖总额
      // 注意：这里应该查询已结算的下注记录，因为结算过程中状态已更新为SETTLED
      const bets = await this.chibiBetRepository.find({
        where: { roundId, status: BetStatus.SETTLED },
      });

      // 计算总下注金额（金币和银币分别计算）
      const totalBetGold = bets.reduce((sum, bet) => {
        return sum + (bet.betGold || 0);
      }, 0);

      const totalBetSilver = bets.reduce((sum, bet) => {
        return sum + (bet.betSilver || 0);
      }, 0);

      // 计算获胜方总中奖金额（使用winGold和winSilver，而不是betGold和betSilver）
      const winningBets = bets.filter((bet) => bet.side === result.winningSide);
      const winningBetGold = winningBets.reduce((sum, bet) => {
        return sum + Number(bet.winGold || 0);
      }, 0);

      const winningBetSilver = winningBets.reduce((sum, bet) => {
        return sum + Number(bet.winSilver || 0);
      }, 0);

      let resultDescription = "";
      if (winningBetGold > 0 && winningBetSilver > 0) {
        resultDescription = `三国鸭胜负已分,获胜国给支持者发放战利品${winningBetGold}金${winningBetSilver}银`;
      } else if (winningBetGold > 0) {
        resultDescription = `三国鸭胜负已分,获胜国给支持者发放战利品${winningBetGold}金0银`;
      } else if (winningBetSilver > 0) {
        resultDescription = `三国鸭胜负已分,获胜国给支持者发放战利品0金${winningBetSilver}银`;
      } else {
        resultDescription = `三国鸭胜负已分,获胜国给支持者发放战利品0金0银`;
      }

      // 构建广播消息 - 赤壁开奖使用act_id: 260
      const broadcastMessage: ChibiBroadcastMessage = {
        act_id: 260, // 赤壁开奖专用指令ID
        code: 0,
        data: {
          c: resultDescription,
          h: new Date().toLocaleTimeString("zh-CN", {
            hour: "2-digit",
            minute: "2-digit",
          }),
          id: Date.now(), // 使用时间戳作为消息ID
          n: "系统",
          rid: 1000,
          t: 6,
        },
      };

      if (totalBetGold > 0 || totalBetSilver > 0) {
        // 保存开奖结果到系统消息表
        try {
          await this.systemMessageService.saveChibiResultMessage(
            broadcastMessage, // 直接传入对象，服务内部会自动格式化
            roundId
          );
          this.logger.log(
            `✅ 赤壁开奖结果已保存到系统消息表，期数: ${roundId}`
          );
        } catch (error: any) {
          this.logger.error(
            `保存赤壁开奖结果到系统消息表失败:`,
            error?.message || error
          );
          // 不影响广播功能，继续执行
        }
      }

      // 通过Redis发布赤壁开奖结果
      this.logger.log(`广播赤壁开奖结果: ${resultDescription}`);
      await this.redisService.publish(
        "casino.chibi.result",
        JSON.stringify(broadcastMessage)
      );
    } catch (error: any) {
      this.logger.error(`❌ 发送赤壁开奖广播失败:`, error?.message || error);
    }
  }

  /**
   * 广播开奖结果给所有在线用户
   */
  private async broadcastDiceResult(
    roundId: number,
    result: DiceResultData
  ): Promise<void> {
    try {
      // 查询本期所有下注，计算实际中奖金额
      const bets = await this.diceBetRepository.find({
        where: { roundId, status: BetStatus.SETTLED },
      });

      // 计算实际中奖金额（金币和银币分别计算）
      const totalWinGold = bets.reduce((sum, bet) => {
        return sum + (bet.currencyType === 1 ? Number(bet.winAmount || 0) : 0);
      }, 0);

      const totalWinSilver = bets.reduce((sum, bet) => {
        return sum + (bet.currencyType === 2 ? Number(bet.winAmount || 0) : 0);
      }, 0);

      // 生成开奖结果描述
      const num1 = result.num1;
      const num2 = result.num2;
      const num3 = result.num3;
      const sum = result.sum;
      const isBig = result.isBig;
      const isSmall = result.isSmall;
      const isOdd = result.isOdd;
      const isEven = result.isEven;
      const isTriple = result.isTriple;

      // 构建开奖结果描述，使用枚举
      let resultDescription = "";
      if (isTriple) {
        const tripleName = getBetTypeFullName(BetType.TRIPLE);
        resultDescription = `本次游乐场乾坤八卦开${num1},${num2},${num3}${tripleName},共奖出${totalWinGold}金${totalWinSilver}银两!`;
      } else {
        // 非豹子情况下，同时显示大小和单双状态
        const sizeName = isBig
          ? getBetTypeFullName(BetType.BIG)
          : getBetTypeFullName(BetType.SMALL);
        const oddEvenName = isOdd
          ? getBetTypeFullName(BetType.ODD)
          : getBetTypeFullName(BetType.EVEN);
        resultDescription = `本次游乐场乾坤八卦开${num1},${num2},${num3}${sizeName}${oddEvenName},共奖出${totalWinGold}金${totalWinSilver}银两!`;
      }

      // 构建广播消息 - 使用act_id: 260
      const broadcastMessage = {
        act_id: 260,
        code: 0,
        data: {
          c: resultDescription,
          h: new Date().toLocaleTimeString("zh-CN", {
            hour: "2-digit",
            minute: "2-digit",
          }),
          id: roundId, // 使用期数ID作为消息ID
          n: "系统",
          rid: 1000,
          t: 6,
        },
      };

      // 保存开奖结果到系统消息表
      if (totalWinGold > 0 || totalWinSilver > 0) {
        try {
          await this.systemMessageService.saveDiceResultMessage(
            broadcastMessage, // 直接传入对象，服务内部会自动格式化
            roundId
          );
          this.logger.log(`✅ 开奖结果已保存到系统消息表，期数: ${roundId}`);
        } catch (error: any) {
          this.logger.error(
            `保存开奖结果到系统消息表失败:`,
            error?.message || error
          );
          // 不影响广播功能，继续执行
        }
      }

      // 通过Redis广播开奖结果
      this.logger.log(`广播大小玩法开奖结果: ${resultDescription}`);
      await this.redisService.publish(
        "casino.dice.result",
        JSON.stringify(broadcastMessage)
      );
    } catch (error: any) {
      this.logger.error(
        `❌ 广播大小玩法开奖结果失败:`,
        error?.message || error
      );
    }
  }

  /**
   * 获取国家名称
   */
  private getSideName(side: number): string {
    const names: { [key: number]: string } = {
      1: "魏国",
      2: "蜀国",
      3: "吴国",
    };
    return names[side] || "未知";
  }

  /**
   * 获取货币名称
   */
  private getCurrencyName(currencyType: number): string {
    return currencyType === 1 ? "金币" : "银币";
  }

  /**
   * 批量结算期数
   */
  async batchSettleRounds(roundIds: number[]): Promise<{
    success: number;
    failed: number;
    errors: string[];
  }> {
    const result = {
      success: 0,
      failed: 0,
      errors: [] as string[],
    };

    for (const roundId of roundIds) {
      try {
        // 先尝试从大小玩法期数表获取
        let round: any = await this.diceRoundService.getRoundById(roundId);
        let gameType = GameType.DICE;

        // 如果不在大小玩法表中，尝试从赤壁玩法期数表获取
        if (!round) {
          round = await this.chibiRoundService.getRoundById(roundId);
          gameType = GameType.CHIBI;
        }

        if (!round) {
          result.errors.push(`期数 ${roundId} 不存在`);
          result.failed++;
          continue;
        }

        switch (gameType) {
          case GameType.DICE:
            await this.settleDiceRound(roundId);
            break;
          case GameType.CHIBI:
            await this.settleChibiRound(roundId);
            break;
          default:
            result.errors.push(`期数 ${roundId} 游戏类型不支持`);
            result.failed++;
            continue;
        }

        result.success++;
      } catch (error: any) {
        result.errors.push(
          `期数 ${roundId} 结算失败: ${error?.message || error}`
        );
        result.failed++;
      }
    }

    this.logger.log(
      `批量结算完成: 成功 ${result.success} 个，失败 ${result.failed} 个`
    );
    return result;
  }

  /**
   * 获取结算统计信息
   */
  async getSettlementStatistics() {
    try {
      // 获取统计信息
      const diceStats = await this.roundService.getRoundStats(GameType.DICE);
      const chibiStats = await this.roundService.getRoundStats(GameType.CHIBI);
      const rpsStats = await this.roundService.getRoundStats(
        GameType.ROCK_PAPER_SCISSORS
      );

      const totalRounds =
        (diceStats?.totalRounds || 0) +
        (chibiStats?.totalRounds || 0) +
        (rpsStats?.totalRounds || 0);
      const settledRounds =
        (diceStats?.settledRounds || 0) +
        (chibiStats?.settledRounds || 0) +
        (rpsStats?.settledRounds || 0);
      const pendingRounds =
        (diceStats?.activeRounds || 0) +
        (chibiStats?.activeRounds || 0) +
        (rpsStats?.activeRounds || 0);

      // 计算总奖金
      const [diceWinnings, chibiWinnings] = await Promise.all([
        this.diceBetRepository
          .createQueryBuilder("bet")
          .select("SUM(bet.winAmount)", "totalWinnings")
          .where("bet.status = :status", { status: BetStatus.SETTLED })
          .getRawOne(),
        this.chibiBetRepository
          .createQueryBuilder("bet")
          .select("SUM(bet.winGold + bet.winSilver)", "totalWinnings")
          .where("bet.status = :status", { status: BetStatus.SETTLED })
          .getRawOne(),
      ]);

      return {
        totalRounds,
        settledRounds,
        pendingRounds,
        totalWinnings:
          parseInt(diceWinnings?.total || "0") +
          parseInt(chibiWinnings?.total || "0"),
      };
    } catch (error: any) {
      this.logger.error(`获取结算统计信息失败:`, error?.message || error);
      return {
        totalRounds: 0,
        settledRounds: 0,
        pendingRounds: 0,
        totalWinnings: 0,
      };
    }
  }

  /**
   * 发送中奖系统消息给玩家
   * @param characterId 角色ID
   * @param gameType 游戏类型
   * @param winAmount 中奖金额
   * @param currencyType 货币类型 (1:金币, 2:银币)
   * @param msgContent 消息内容
   */
  private async sendWinningSystemMessage(
    characterId: number,
    gameType: string,
    winAmount: number,
    currencyType: number,
    msgContent?: string
  ): Promise<void> {
    try {
      // 构建中奖消息内容
      const currencyName = currencyType === 1 ? "金币" : "银币";
      const messageContent =
        msgContent ||
        `恭喜,您在${gameType}中中奖，获得${winAmount}${currencyName}！`;

      // 构建个人消息体格式
      const personalMessageBody = {
        content: messageContent,
        date: new Date().toLocaleTimeString("zh-CN", {
          hour: "2-digit",
          minute: "2-digit",
          second: "2-digit",
        }),
        fname: "系统信息",
      };

      // 1. 保存个人消息到系统消息表
      try {
        await this.systemMessageService.savePersonalMessage(
          personalMessageBody, // 直接传入对象，服务内部会自动格式化
          characterId,
          1000, // 系统角色ID
          "系统"
        );

        this.logger.log(
          `✅ 中奖系统消息已保存到系统消息表: 角色${characterId} 在${gameType}中奖`
        );
      } catch (error: any) {
        this.logger.error(
          `❌ 保存中奖系统消息到系统消息表失败: 角色${characterId}`,
          error?.message || error
        );
        // 即使保存失败，也继续执行Redis发布，确保消息能推送
      }

      // 2. 通过Redis发布中奖通知，WebSocket网关会订阅并推送
      this.redisService.publish(
        "casino.winning.notification",
        JSON.stringify({
          messageContent: personalMessageBody,
          receiverCharacterId: characterId,
        })
      );

      this.logger.log(
        `✅ 中奖通知已发布: 角色${characterId} 在${gameType}中奖`
      );
    } catch (error: any) {
      this.logger.error(
        `❌ 发布中奖通知失败: 角色${characterId}`,
        error?.message || error
      );
    }
  }
}
